// 实现MQTT端业务的相关
#include "mqttClient.h"
#include "define.h"
#include "ctrl.h"
#include "cjson/cJSON.h"
#include "zlog.h"
#include <pthread.h>
#include "security_manage.h"
#include "iotaimp.h"
#include "JsonParser.h"
#include "BussinessTerminalManage.h"
#include "ota.h"
#include "map.h"
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>

#define NODE_STEP 5

PFUN_PRO_COMMON g_pFunTerminalSyncTime = NULL;
PFUN_PRO_COMMON g_pFunTerminalReboot = NULL; //
PFUN_PRO_COMMON g_pFunTerminalLog = NULL;
PFUN_PRO_COMMON g_pFunTerminalLogLevel = NULL;
PFUN_PRO_COMMON g_pFunSecurityProc = NULL;
PFUN_PRO_COMMON g_pFunTerminalUpdate = NULL;
PFUN_PRO_COMMON g_pFunFirmwareDownload = NULL;
PFUN_PRO_COMMON g_pFunFirmwareUpgrade = NULL;
PFUN_PRO_COMMON g_pFunactionPatchDownload = NULL;
PFUN_PRO_COMMON g_pFunactionConfigDownalod = NULL;
PFUN_PRO_COMMON g_pFunactionConfigUpgrade = NULL;
PFUN_PRO_COMMON g_pFunSecurityCommond = NULL;
PFUN_PRO_COMMON g_pFunTerminalSetConfig = NULL;
PFUN_PRO_COMMON g_pFunTerminalCallLinkTrace = NULL;
PFUN_PRO_COMMON g_pFunsetFullReport = NULL;
PFUN_PRO_COMMON g_pFundataSpaceService = NULL;
PFUN_PRO_COMMON g_pFunTerminalAppCommond = NULL;
PFUN_PRO_COMMON g_pFunTerminalConCommond = NULL;
PFUN_PRO_COMMON g_pFunSafeCommond = NULL;
PFUN_PRO_COMMON g_pFunVulnPolicy = NULL;
PFUN_PRO_COMMON g_pPwqualityConfig = NULL;
PFUN_PRO_COMMON g_pKpatchConfig = NULL;
PFUN_PRO_COMMON g_pFunTerminalDirCommond = NULL;
PFUN_PRO_COMMON g_pFunTerminalOTACommond = NULL;
PFUN_PRO_COMMON g_pFunnetDelayTest = NULL;
PFUN_PRO_REPORT g_pFunTerminalManage = NULL;        // baseinfo report
PFUN_PRO_REPORT g_pFunTerminalPublish = NULL;       // Terminal publish
PFUN_PRO_REPORT g_pFunLogPublish = NULL;            // log publish
PFUN_PRO_REPORT g_pFunConfManage = NULL;            // 第三应用配置下发
PFUN_PRO_REPORT g_pFunTerminal_Init = NULL;         // 平台新增台账时触发，当触发时上报baseInfo,重新拉去物联配置
PFUN_PRO_REPORT g_pFunUsbPlugging = NULL;
PFUN_PRO_REPORT g_pFunStartDepend = NULL;
PFUN_PRO_REPORT g_pFunUpdateCer = NULL;
PFUN_PRO_REPORT g_pFunrealTimeMonitoring = NULL; // 实时监控
PFUN_PRO_REPORT g_pFunSubDeviceAuth = NULL;         //子设备增强认证
PFUN_PRO_REPORT g_pFunSwitchIotAuth = NULL;         //切换物联连接方式
PFUN_PRO_REPORT g_pFunQueryScram = NULL;         //
PFUN_PRO_REPORT g_pFunpo_policy = NULL;
PFUN_PRO_REPORT g_pFunpo_setBaselineCheck = NULL;

// 第三方对接
PFUN_PRO_REPORT g_pFunThirdModule = NULL;
// 电力线载波网管
PFUN_PRO_REPORT g_pFunPlcModule = NULL;
extern ob_context g_mqtt_ob;
extern int g_mqtt_issucc;
int start = 0;
extern map_void_t g_SubDeviceID;
extern map_void_t g_CcoStaDeviceID;
extern zlog_category_t *BD_zlog;
extern zlog_category_t *PLCC_zlog;
extern char *LOGIN_USER;
extern char *LOGIN_PASSWORD;
static map_void_t g_BDLocalInfo;
static uint8_t g_iFrameSeq = 0;                     //计量协议帧序列号
static uint16_t g_iLastStartNo = 0;
static bool g_bIsQuering = false;

typedef struct BDLocalInfo
{
    char mid[80];
    char zone[10];
    char node[10];
    char service[60];
} BDLocalInfo;

//计量协议帧打包    iAFN:应用功能码，iD1:数据标识编码，psContent：数据内容
void PackJLFrame(uint8_t iAFN,uint32_t iD1,const uint8_t *psContent,uint16_t iLen,uint8_t *psBuf,uint16_t *piSize)
{
    int iSize = 12 + iLen;                      //帧头10字节，帧尾2字节
    memset(psBuf,0,iSize);

    psBuf[0] = 0x68;
    memcpy(psBuf+1,&iSize,2);                //总长度
    psBuf[3] = 0x40;                         //控制域
    psBuf[4] = iAFN;
    psBuf[5] = g_iFrameSeq++;                //序列号
    memcpy(psBuf+6,iD1,4);

    //数据内容
    memcpy(psBuf+10,psContent,iLen);

    //校验和
    uint8_t iCheckSum = 0;
    for(int i=3;i<=iSize-3;i++)
        iCheckSum += psBuf[i];

    psBuf[iSize-2] = iCheckSum;
    psBuf[iSize-1] = 0x16;
    *piSize = iSize;
}

//计量协议帧打包
int UnPackJLFrame(const uint8_t *psBuf,uint16_t iSize,uint8_t *piAFN,uint32_t *piD1,uint8_t *psContent,uint16_t *piLen)
{
    uint16_t iLength = *((uint16_t*)(psBuf + 1));
    printf("UnPackJLFrame:---------len:%d\n",iLength);

    if(iLength != iSize)
    {
        printf("UnPackJLFrame:---------data size error!(size:%d)\n",iSize);
        return -1;
    }

    *piAFN = (uint8_t)psBuf[4];
    *piD1 = *((uint32_t*)(psBuf + 6));

    //数据内容
    memcpy(psContent,psBuf+10,iSize-12);
    *piLen = iSize-12;
    return 0;
}

void netDelayTest(char *buf)
{
    int ret;
    // 投递消息（解耦）
    if (g_mqtt_ob.netPq)
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        long long milliseconds = (long long)(tv.tv_sec) * 1000 + (long long)(tv.tv_usec) / 1000;
        char *buff = (char *)malloc(strlen(buf) + 1);
        strncpy(buff, buf, strlen(buf));
        ret = cQPost(g_mqtt_ob.netPq, (void *)buff);
        if (ret == ERR_Q_FULL)
        {
            dzlog_error("cQPost error , queue is full");
            free(buff);
        }
    }
}

char *getModule(const char *input)
{

    char *token;
    int count = 0;           // 用于计数子字符串
    char *thirdToken = NULL; // 用于存储第三个子字符串
    // 使用 strtok 分割字符串
    token = strtok(input, "/");
    while (token != NULL)
    {
        count++; // 每次获取一个子字符串，计数加1
        if (count == 4)
        {
            thirdToken = token; // 如果是第三个子字符串，保存它
            break;              // 提前退出循环
        }
        token = strtok(NULL, "/"); // 继续分割
    }
    // 输出第三个子字符串
    if (thirdToken != NULL)
    {
        printf("Module: %s\n", thirdToken);
    }
    else
    {
        printf("Module not found.\n");
    }
    return thirdToken;
}
void proMsg(char *top, char *buf, int size) // 处理业务
{
    // 处理本地MQTT服务推送过来的消息
    if (strcmp(top, "PLCService/notify/spont/*/accessNetDevAlaram") == 0 || strcmp(top, "sys.base/notify/spont/*/accessNetDeyAlaram") == 0 ||
        strcmp(top, "/sys.brd/sys.base/S-selfdiscovery/F-NewDevAccess") == 0 || strstr(top, "/ext.syy.mccb/") != NULL || strstr(top, "SyyMccb/") != NULL)
    {
        //消息来自MCCB
        if (strstr(top, "/ext.syy.mccb/") != NULL || strstr(top, "SyyMccb/") != NULL)
        {
            if (strstr(top, "/F-VerifySign") != NULL) /// ext.syy.phSmc/ext.syy.mccb/S-smclink/F-VerifySign
                handleSecReq(buf);
            else if (strstr(top, "/F-ReportDeviceInfo") != NULL) /// ext.syy.phSmc/ext.syy.mccb/S-smclink/F-ReportDeviceInfo
                handleDeviceInfo(buf);
            else if (strstr(top, "/S-dataservice/F-UpdateDevStatus") != NULL || strstr(top, "SyyMccb/notify") != NULL) /// sys.brd/ext.syy.mccb/S-dataservice/F-UpdateDevStatus
                handleDeviceStatus(buf);
        }
        else if (strstr(top,"svc.tasksched") != NULL)           //消息来自采集调度
        {
            if (strstr(top, "F-ProxyFrame") != NULL)           /// /ext.syy.phSmc/svc.tasksched/S-meter/F-ProxyFrame
                handleAuthInfo(buf);
            else if(strstr(top,"F-ReportEvent") != NULL)      ///svc.brd/svc.tasksched/S-meter/F-ReportEvent
                handleReportEvent(buf);
        }
        else
        {
            dzlog_info("recvMsg buf(%s) from accessNetDevAlaram", buf);
            handleLocalSubscribeMsg(buf);
        }
        return;
    }

    // 转发消息到变电组件
    if (strstr(top, "/Cloud_BdPortal/") != NULL)
    {
        if (strstr(top, "/Cloud_BdPortal/getEagleEyeLog") != NULL)
        {
            // 涉及文件上传 单独开一个线程处理
            // 分线程
            pthread_t thread;
            pthread_attr_t attr;
            char *psJson = strdup(buf);
            // 初始化线程属性
            pthread_attr_init(&attr);

            // 将线程设置为分离状态
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

            // 创建线程
            pthread_create(&thread, &attr, handleBDLog, psJson);
            // 销毁线程属性对象
            pthread_attr_destroy(&attr);
            return;
        }

        handleLocalBDEvent(buf, top);
        return;
    }
    if (strstr(top, "/LocalMqtt/BianDian/V1/Cloud_BdPortal_Res/") != NULL)
    {
        if (strstr(top, "/Cloud_BdPortal_Res/messageReport") != NULL)
        {
            handleBDMessageReport(top, buf);
            return;
        }

        handleLocalBDBackEvent(buf, top);
        return;
    }

    //TODO-YZ:PLCC
    //上行：
    if (strstr(top, "/ext.syy.phSmc/ext.syy.plcc/S-smclink/F-PlccEvent") != NULL)
    {
	    handleLocalPlccEvent(top, buf);
            return;
    }
    //下行：
    if (strstr(top, "/app/cloudProgram") != NULL)
    {
	    handlePlccEvent(top, buf);
            return;
    }


    dzlog_info("Message_arrived topicName[%s] buf[%.*s]\n", top, size,buf);

    char *pModule = getModule(top);
    int ret = -1;
    char cmd[32] = {0};
    char service[40] = {0};
    cJSON *json = NULL;
    json = cJSON_Parse(buf);
    if (json)
    {
        if (!cJSON_HasObjectItem(json, "cmd"))
        {
            cJSON_Delete(json);
            return;
        }

        strcpy(cmd, cJSON_GetObjectItem(json, "cmd")->valuestring);
        cJSON* serviceTmpObj = cJSON_GetObjectItem(json, "service");
        if (serviceTmpObj)
        {
            strcpy(service, cJSON_GetObjectItem(json, "service")->valuestring);
        }

        if (strcmp("actionSystemReboot", cmd) == 0)
        {
            if (g_pFunTerminalReboot)
            {
                // dzlog_info("g_pFunTerminalReboot start");
                g_pFunTerminalReboot(buf);

                // dzlog_info("g_pFunTerminalReboot end");
            }
        }
        else if (strcmp("actionSyncTime", cmd) == 0)
        {

            if (g_pFunTerminalSyncTime)
            {
                // dzlog_info("g_pFunTerminalSyncTime start");
                g_pFunTerminalSyncTime(buf);
                // dzlog_info("g_pFunTerminalSyncTime end");
            }
        }
        else if (strcmp("actionExtractLog", cmd) == 0)
        {
            if (g_pFunTerminalLog)
            {
                // dzlog_info("g_pFunTerminalLog start");
                g_pFunTerminalLog(buf);
                // dzlog_info("g_pFunTerminalLog end");
            }
        }
        else if (strcmp("setAlarmThresholdConfig", cmd) == 0)
        {
            if (g_pFunSecurityProc)
            {
                // dzlog_info("g_pFunSecurityProc start");
                g_pFunSecurityProc(buf);
                // dzlog_info("g_pFunSecurityProc end");
            }
        }
        else if (strcmp("setDataReportConfig", cmd) == 0)
        {
            if (g_pFunTerminalSetConfig)
            {
                // dzlog_info("g_pFunTerminalSetConfig start");
                g_pFunTerminalSetConfig(buf);
                // dzlog_info("g_pFunTerminalSetConfig end");
            }
        }

        else if (strcmp("callLinkTrace", cmd) == 0)
        {
            if (g_pFunTerminalCallLinkTrace)
            {
                // dzlog_info("g_pFunTerminalCallLinkTrace start");
                g_pFunTerminalCallLinkTrace(buf);
                // dzlog_info("g_pFunTerminalCallLinkTrace end");
            }
            else
            {
                // dzlog_info("g_pFunTerminalCallLinkTrace start 111");
            }
        }
        else if (strcmp("setLogRegex", cmd) == 0)
        {
            if (g_pFunTerminalLogLevel)
            {
                // dzlog_info("g_pFunTerminalLog start");
                g_pFunTerminalLogLevel(buf);
                // dzlog_info("g_pFunTerminalLog end");
            }
        }
        else if (strcmp("security", service) == 0)
        {
            // dzlog_info("security start");
            if (g_pFunSecurityCommond)
            {
                // dzlog_info("g_pFunSecurityCommond start");
                g_pFunSecurityCommond(buf);
                // dzlog_info("g_pFunSecurityCommond end");
            }
        }
        else if (strcmp("app", service) == 0)
        {
            if (g_pFunTerminalAppCommond)
            {
                // dzlog_info("g_pFunTerminalAppCommond start");
                g_pFunTerminalAppCommond(buf);
                // dzlog_info("g_pFunTerminalAppCommond end");
            }
        }
        else if (strcmp("virtualization", service) == 0)
        {
            // dzlog_info("virtualization start");
            if (g_pFunTerminalConCommond)
            {
                // dzlog_info("g_pFunTerminalConCommond start");
                g_pFunTerminalConCommond(buf);
                // dzlog_info("g_pFunTerminalConCommond end");
            }
        }
        else if (strcmp("upgrade", cmd) == 0)
        {
            if (g_pFunTerminalUpdate)
            {
                // dzlog_info("g_pFunTerminalUpdate start");
                g_pFunTerminalUpdate(buf);
                // dzlog_info("g_pFunTerminalUpdate end");
            }
        }
        else if (strcmp("actionPatchDownload", cmd) == 0)
        {
            if (g_pFunactionPatchDownload)
            {
                // dzlog_info("g_pFunactionPatchDownload start");
                g_pFunactionPatchDownload(buf);
                // dzlog_info("g_pFunactionPatchDownload end");
            }
        }
        else if (strcmp("actionConfigDownload", cmd) == 0)
        {
            if (g_pFunactionConfigDownalod)
            {
                // dzlog_info("g_pFunactionConfigDownalod start");
                g_pFunactionConfigDownalod(buf);
                // dzlog_info("g_pFunactionConfigDownalod end");
            }
        }
        else if (strcmp("actionPatchInstall", cmd) == 0 || strcmp("actionConfigUpgrade", cmd) == 0)
        {
            if (g_pFunactionConfigUpgrade)
            {
                // dzlog_info("g_pFunactionConfigUpgrade start");
                g_pFunactionConfigUpgrade(buf);
                // dzlog_info("g_pFunactionConfigUpgrade end");
            }
        }
        else if (strcmp("actionFirmwareDownload", cmd) == 0)
        {
            if (g_pFunFirmwareDownload)
            {
                // dzlog_info("g_pFunFirmwareDownload start");
                g_pFunFirmwareDownload(buf);
                // dzlog_info("g_pFunFirmwareDownload end");
            }
        }
        else if (strcmp("actionFirmwareUpgrade", cmd) == 0)
        {
            if (g_pFunFirmwareUpgrade)
            {
                // dzlog_info("g_pFunFirmwareUpgrade start");
                g_pFunFirmwareUpgrade(buf);
                // dzlog_info("g_pFunFirmwareUpgrade end");
            }
        }
        else if (strcmp("setFullReport", cmd) == 0)
        {
            if (g_pFunsetFullReport)
            {
                // dzlog_info("g_pFunsetFullReport start");
                g_pFunsetFullReport(buf);
                // dzlog_info("g_pFunsetFullReport end");
            }
        }
        else if (strcmp("setDataSpaceReport", cmd) == 0)
        {
            if (g_pFundataSpaceService)
            {
                // dzlog_info("g_pFundataSpaceService start");
                g_pFundataSpaceService(buf);
                // dzlog_info("g_pFundataSpaceService end");
            }
        }
        else if (strcmp("setFileMonitorConfig", cmd) == 0)
        {
            if (g_pFunSafeCommond)
            {
                // dzlog_info("g_pFunSafeCommond start");
                g_pFunSafeCommond(buf);
                // dzlog_info("g_pFunSafeCommond end");
            }
        }
        else if (strcmp("setVulnsConfig", cmd) == 0)
        {
            if (g_pFunVulnPolicy)
            {
                // dzlog_info("g_pFunSafeCommond start");
                g_pFunVulnPolicy(buf);
                // dzlog_info("g_pFunSafeCommond end");
            }
        }
        else if (strcmp("setPwqualityConfig", cmd) == 0)
        {
            if (g_pPwqualityConfig)
            {
                // dzlog_info("g_pFunSafeCommond start");
                g_pPwqualityConfig(buf);
                // dzlog_info("g_pFunSafeCommond end");
            }
        }
        else if (strcmp("setKpatchConfig", cmd) == 0)
        {
            if (g_pKpatchConfig)
            {
                // dzlog_info("g_pFunSafeCommond start");
                g_pKpatchConfig(buf);
                // dzlog_info("g_pFunSafeCommond end");
            }
        }

        else if (strcmp("netDelayTest", cmd) == 0)
        {
            if (g_pFunnetDelayTest)
            {
                struct timeval tv;
                gettimeofday(&tv, NULL);
                long long milliseconds = (long long)(tv.tv_sec) * 1000 + (long long)(tv.tv_usec) / 1000;
                cJSON_AddNumberToObject(json, "recvTime", milliseconds);
                char* tmpJson = cJSON_PrintUnformatted(json);
                g_pFunnetDelayTest(tmpJson);
                free(tmpJson);
            }
        }
        else if (strcmp("deviceProfileService", service) == 0)
        {
            if (g_pFunConfManage)
            {
                // dzlog_info("g_pFunConfManage start");
                g_pFunConfManage(buf);
                // dzlog_info("g_pFunConfManage end");
            }
        }
        else if (strcmp("realTimeMonitoring", service) == 0)
        {
            if (g_pFunrealTimeMonitoring)
            {
                g_pFunrealTimeMonitoring(buf);
            }
        }
        else if (strcmp("dictionary", service) == 0)
        {
            if (g_pFunTerminalDirCommond)
            {
                // dzlog_info("g_pFunTerminalDirCommond start");
                g_pFunTerminalDirCommond(buf);
                // dzlog_info("g_pFunTerminalDirCommond end");
            }
        }
        else if (strcmp("otaManageService", service) == 0)
        {
            if (g_pFunTerminalOTACommond)
            {
                dzlog_info("g_pFunTerminalOTACommond start");
                g_pFunTerminalOTACommond(buf);
                dzlog_info("g_pFunTerminalOTACommond end");
            }
        }
        else if (strcmp("init", cmd) == 0)
        {
            if (g_pFunTerminal_Init)
            {
                g_pFunTerminal_Init(buf);
            }
        }
        else if (strcmp("usbPlugging", service) == 0)
        {
            if (g_pFunUsbPlugging)
            {
                // dzlog_info("g_pFunUsbPlugging start");
                g_pFunUsbPlugging(buf);
                // dzlog_info("g_pFunUsbPlugging end");
            }
        }
        else if (strcmp("startDepend", cmd) == 0)
        {
            if (g_pFunStartDepend)
            {
                // dzlog_info("g_pFunStartDepend start");
                g_pFunStartDepend(buf);
                // dzlog_info("g_pFunStartDepend end");
            }
        }
        else if (strcmp("updateCer", cmd) == 0)
        {
            if (g_pFunUpdateCer)
            {
                g_pFunUpdateCer(buf);
            }
        }
        else if (strcmp("third", pModule) == 0)
        {
            if (g_pFunThirdModule)
            {
                // dzlog_info("g_pFunThirdModule start");
                g_pFunThirdModule(buf);
                // dzlog_info("g_pFunThirdModule end");
            }
        }
        else if (strcmp("plc", pModule) == 0)
        {
            dzlog_info("g_pFunPlcModule start....");
            if (g_pFunPlcModule)
            {
                dzlog_info("g_pFunPlcModule start");
                g_pFunPlcModule(buf);
                // dzlog_info("g_pFunPlcModule end");
            }
        }
        else if (strcmp("actionSubDeviceAuthorize", cmd) == 0)
        {
            if (g_pFunSubDeviceAuth)
            {
                g_pFunSubDeviceAuth(buf);
            }
        }
        else if (strcmp("IsEnableScram", cmd) == 0)
        {
            if (g_pFunQueryScram)
            {
                g_pFunQueryScram(buf);
            }
        }
        else if (strcmp("setProactiveOutreach", cmd) == 0)
        {
            if (g_pFunpo_policy)
            {
                g_pFunpo_policy(buf);
            }
        }
        else if (strcmp("setBaselineCheck", cmd) == 0)
        {
            if (g_pFunpo_setBaselineCheck)
            {
                g_pFunpo_setBaselineCheck(buf);
            }
        }

        cJSON_Delete(json);
    }
    else
    {
        // dzlog_info("proMsg  cJSON_Parse error");
    }
}

int g_login = 0;
int g_TerminalPublish = 0;
char *g_query_message;
extern ob_context g_mqtt_ob;

//----------------可删除 start-----------------------
void Test_Logout()
{
    int ret = IOTA_Logout();
    printf("MQTT_Demo: Test_Logout(), ret = %d \n", ret);
}

void Test_updateDeviceStatusOnline(char *strDeviceId)
{
    static int mid = 3000;

    IOTA_DeviceStatusUpdate(++mid, strDeviceId, "ONLINE");
}

void Test_updateDeviceStatusOffline(char *strDeviceId)
{
    static int mid = 4000;

    IOTA_DeviceStatusUpdate(++mid, strDeviceId, "OFFLINE");
}

void Test_DataReport(char *strDeviceId)
{
    char *strData = "{\"key\":\"value\"}";

    int messageId = IOTA_ServiceDataReport(strDeviceId, g_mqtt_ob.clientInfo.service_id, strData);

    printf("MQTT_Demo: Test_DataReport(), report data with messageId %d \n", messageId);
}

void Test_addSubDevice(char *strDeviceId)
{
    static int mid = 1000;
    ST_IOTA_DEVICE_INFO device;
    device.pcNodeId = strDeviceId;
    device.pcDeviceId = "";
    device.pcName = "";
    device.pcDescription = "";
    device.pcManufacturerId = g_mqtt_ob.clientInfo.manufacturerId;
    device.pcModel = g_mqtt_ob.clientInfo.model;
    IOTA_HubDeviceAdd(++mid, &device);
}

void Test_deleteSubDevice(char *strDeviceId)
{
    static int mid = 5000;

    ST_IOTA_DEVICE_INFO device;
    device.pcNodeId = "";
    device.pcDeviceId = strDeviceId;
    device.pcName = "";
    device.pcDescription = "";
    device.pcManufacturerId = g_mqtt_ob.clientInfo.manufacturerId;
    device.pcManufacturerName = g_mqtt_ob.clientInfo.manufacturerName;
    device.pcModel = g_mqtt_ob.clientInfo.model;

    IOTA_HubDeviceRemove(++mid, strDeviceId);
}

void Test_commandResponse(int mid)
{
    char *strData = "{\"commandresult\":\"123\"}";
    int messageId = IOTA_ServiceCommandResponse(mid, 0, strData);
    printf("MQTT_Demo: Test_commandResponse(), response data with messageId %d, command mid %d \n", messageId, mid);
}

void Test_queryDeviceInfo(char *pcNodeId)
{
    static int mid = 2000;

    ST_IOTA_DEVICE_INFO device;
    if (pcNodeId == NULL)
    {
        device.pcNodeId = g_mqtt_ob.clientInfo.device_id;
    }
    else
    {
        device.pcNodeId = pcNodeId;
    }
    device.pcDeviceId = "";
    device.pcName = "";
    device.pcDescription = "";
    device.pcManufacturerId = g_mqtt_ob.clientInfo.manufacturerId;
    device.pcModel = g_mqtt_ob.clientInfo.model;
    IOTA_HubDeviceQuery(++mid, NULL, 0, &device);
}

void Test_CustomTopicReport(char *strDeviceId)
{
    ST_IOTA_BatchReportProperties brp = {0};
    brp.pcDeviceId = strDeviceId;
    brp.pcServiceId = g_mqtt_ob.clientInfo.service_id;
    brp.pcPayload = "{\"key\":\"value\"}";

    int messageId = IOTA_ServiceCustomTopicReport(&brp, "v2.0", "MQTTNTP");

    printf("MQTT_Demo: Test_CustomTopicReport(), report data with messageId %d \n", messageId);
}

void Test_CustomTopicSubscribe()
{

    int messageId = IOTA_SubscribeCustomTopic("v2.0", "MQTTNTPResponse");

    printf("MQTT_Demo: Test_CustomTopicSubscribe(), report data with messageId %d \n", messageId);
}

/* int logincount = 0; */
void handleLoginSuccess(void *context, int messageId, int code, char *message)
{
    dzlog_info("MQTT_Demo: handleLoginSuccess(), login success1");
    g_login = 1;
    g_mqtt_issucc = 1;
    // 链接成功上报一次
    if (g_pFunTerminalManage)
        g_pFunTerminalManage();
    dzlog_info("MQTT_Demo: handleLoginSuccess(), login success2");
    // 升级后检测
    otaEagleEyeSMG_updated_check();

    if (calculate_file_size("update.tmp") > 0 && calculate_file_size("update.json") > 0)
    {
        char buffer[2048] = {0};
        FILE *fp = fopen("update.json", "r");
        fgets(buffer, sizeof(buffer), fp);
        ServiceUpdate(buffer, true);
        fclose(fp);
    }
    ///
}

void handleLoginFailure(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleConnectFailure() error, code %d, messsage %s\n", code, message);

}

void handleConnectionLost(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleConnectionLost() warning, code %d, messsage %s\n", code, message);

    g_login = 0;
}

void handleSubscribeSuccess(void *context, int messageId, int code, char *message)
{
    // printf("MQTT_Demo: handleSubscribeSuccess() messageId %d\n", messageId);
}

void handleSubscribeFailure(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleSubscribeFailure() warning, messageId %d, code %d, messsage %s\n", messageId, code, message);
}

void handlePublishSuccess(void *context, int messageId, int code, char *message)
{

    terminalSend();
}

void handlePublishFailure(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handlePublishFailure() warning, messageId %d, code %d\n", messageId, code);
    terminalLoss();
}

void handleLogoutSuccess(void *context, int messageId, int code, char *message)
{
    printf("AgentLiteDemo: handleLogoutSuccess, login again\n");
    g_login = 0;
}

void handleLogoutFailure(void *context, int messageId, int code, char *message)
{
    printf("AgentLiteDemo: handleLogoutFailure, login again\n");
    int ret = IOTA_Login();
    if (ret != 0)
    {
        printf("MQTT_Demo: handleConnectionLost() error, login again failed, result %d\n", ret);
    }
}

void handleCommandArrived(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleCommandArrived(), messageId %d, code %d, messsage %s\n", messageId, code, message);
}

void handleCustomTopicMessageArrived(void *context, int messageId, int code, const char *topic, char *message)
{
    printf("MQTT_Demo: handleCustomTopicMessageArrived(), messageId %d, code %d, topic %s, messsage %s\n", messageId, code, topic, message);
}

void JsonToStruct_DeviceAddRsp_my(const char *strJson)
{
    cJSON *json = NULL;
    cJSON *dataList = NULL;
    cJSON *data = NULL;
    cJSON *dev = NULL;
    json = cJSON_Parse(strJson);
    if (json)
    {
        dataList = cJSON_GetObjectItem(json, "data");
        int i = 0;
        for (; i < cJSON_GetArraySize(dataList); i++)
        {
            data = cJSON_GetArrayItem(dataList, i);
            if (cJSON_HasObjectItem(data, "deviceInfo"))
            {
                dev = cJSON_GetObjectItem(data, "deviceInfo");
            }
            break;
        }

        cJSON_Delete(json);
    }
    return;
}

void handleSubDeviceAddResult(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleSubDeviceAddResult(), messageId %d, code %d, messsage %s\n", messageId, code, message);
    JsonToStruct_DeviceAddRsp_my(message);
}

void handleSubDeviceDeleteResult(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleSubDeviceDeleteResult(), messageId %d, code %d, messsage %s\n", messageId, code, message);
}

void handleSubDeviceUpdateResult(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleSubDeviceUpdateResult(), messageId %d, code %d, messsage %s\n",
           messageId, code, message);
}

void handleDeviceQueryResult(void *context, int messageId, int code, char *message)
{
    printf("MQTT_Demo: handleDeviceQueryResult(), messageId %d, code %d, messsage %s\n", messageId, code, message);
    g_query_message = message;
}

void Test_Login()
{
    int ret = IOTA_Login();
    printf("MQTT_Demo: Test_Login(), ret = %d \n", ret);
}

void setMyCallbacks()
{
    IOTA_SetCallback(EN_IOTA_CALLBACK_CONNECT_SUCCESS, handleLoginSuccess);
    IOTA_SetCallback(EN_IOTA_CALLBACK_CONNECT_FAILURE, handleLoginFailure);
    IOTA_SetCallback(EN_IOTA_CALLBACK_CONNECTION_LOST, handleConnectionLost);

    IOTA_SetCallback(EN_IOTA_CALLBACK_DISCONNECT_SUCCESS, handleLogoutSuccess);
    IOTA_SetCallback(EN_IOTA_CALLBACK_DISCONNECT_FAILURE, handleLogoutFailure);

    IOTA_SetCallback(EN_IOTA_CALLBACK_SUBSCRIBE_SUCCESS, handleSubscribeSuccess);
    IOTA_SetCallback(EN_IOTA_CALLBACK_SUBSCRIBE_FAILURE, handleSubscribeFailure);

    IOTA_SetCallback(EN_IOTA_CALLBACK_PUBLISH_SUCCESS, handlePublishSuccess);
    IOTA_SetCallback(EN_IOTA_CALLBACK_PUBLISH_FAILURE, handlePublishFailure);

    IOTA_SetCallback(EN_IOTA_CALLBACK_COMMAND_ARRIVED, handleCommandArrived);

    IOTA_SetCallback(EN_IOTA_CALLBACK_DEVICE_ADDITION_RESULT, handleSubDeviceAddResult);
    IOTA_SetCallback(EN_IOTA_CALLBACK_DEVICE_DELETION_RESULT, handleSubDeviceDeleteResult);
    IOTA_SetCallback(EN_IOTA_CALLBACK_DEVICE_UPDATE_RESULT, handleSubDeviceUpdateResult);
    IOTA_SetCallback(EN_IOTA_CALLBACK_DEVICE_QUERY_RESULT, handleDeviceQueryResult);

    IOTA_SetCallbackWithTopic(handleCustomTopicMessageArrived);
}

//----------------可删除 end-----------------------

void readMQTTClientCfg(dictionary *ini, ST_CLIENT_INFO *mqttClient)
{
    mqttClient->port = iniparser_getint(ini, "mqtt_client:port", -1);
    mqttClient->keepAlivetime = iniparser_getint(ini, "mqtt_client:keepAlivetime", -1);
    mqttClient->server_addr = iniparser_getstring(ini, "mqtt_client:server_addr", "NULL");
    mqttClient->device_id = iniparser_getstring(ini, "mqtt_client:device_id", "NULL");
    mqttClient->client_id = iniparser_getstring(ini, "mqtt_client:device_id", "NULL");
    // mqttClient->service_id = iniparser_getstring(ini, "mqtt_client:service_id", "NULL");
    mqttClient->manufacturerId = iniparser_getstring(ini, "mqtt_client:ManufacturerId", "NULL");
    mqttClient->manufacturerName = iniparser_getstring(ini, "mqtt_client:ManufacturerName", "NULL");
    mqttClient->model = iniparser_getstring(ini, "mqtt_client:Model", "NULL");
    mqttClient->prefix = iniparser_getstring(ini, "mqtt_client:prefix", "NULL");
    mqttClient->SSL = iniparser_getint(ini, "mqtt_client:SSL", 2);
    mqttClient->sencrypt = iniparser_getint(ini, "mqtt_client:sencrypt", 1);
    mqttClient->user_name = iniparser_getstring(ini, "mqtt_client:user_name", "NULL");
    mqttClient->passwd = iniparser_getstring(ini, "mqtt_client:passwd", "NULL");
    mqttClient->is_ipv6 = iniparser_getint(ini, "mqtt_client:ipv6", 0);
    mqttClient->scram = iniparser_getint(ini, "mqtt_client:scram", 0);

  
}

void setLoginConfig()
{
    IOTA_ConfigSetStr(EN_IOTA_CFG_MQTT_ADDR, g_mqtt_ob.clientInfo.server_addr);
    IOTA_ConfigSetUint(EN_IOTA_CFG_MQTT_PORT, g_mqtt_ob.clientInfo.port);
    IOTA_ConfigSetStr(EN_IOTA_CFG_DEVICEID, g_mqtt_ob.clientInfo.device_id);
    IOTA_ConfigSetStr(EN_IOTA_CFG_CLIENTID, g_mqtt_ob.clientInfo.client_id);
    IOTA_ConfigSetStr(EN_IOTA_CFG_DEVICESECRET, g_mqtt_ob.clientInfo.passwd);
    IOTA_ConfigSetStr(EN_IOTA_CFG_USERNAME, g_mqtt_ob.clientInfo.user_name);

    IOTA_ConfigSetUint(EN_IOTA_CFG_KEEP_ALIVE_TIME, g_mqtt_ob.clientInfo.keepAlivetime);
    IOTA_ConfigSetUint(EN_IOTA_CFG_MQTT_URL_PREFIX,
                       g_mqtt_ob.clientInfo.port == 8443 ? EN_IOTA_CFG_URL_PREFIX_SSL : EN_IOTA_CFG_URL_PREFIX_TCP);
    IOTA_ConfigSetUint(EN_IOTA_CFG_AUTH_MODE, EN_IOTA_CFG_AUTH_MODE_NODE_ID);
    IOTA_ConfigSetUint(EN_IOTA_CFG_QOS, 0);
    IOTA_ConfigSetUint(EN_IOTA_CFG_SSL, g_mqtt_ob.clientInfo.SSL);
}

void *publish_thread(void *param)
{
    pthread_detach(pthread_self());

    while (1)
    {
        // 注意下面的回调函数执行不要阻塞
        // 1终端监控上报
        if (g_pFunTerminalPublish && g_login)
        {
            g_pFunTerminalPublish();
        }
        sleep(3);
    }
}

void *sys_log_publish_thread(void *param)
{
    pthread_detach(pthread_self());

    while (1)
    {
        if (g_login)
        {
            sys_log_publish_oe();
        }
        sleep(10);
    }
}

void keep_alive_thread()
{
    char uuid[80] = {0};
    int ret = 0;
    dzlog_info("KeepAlive start");
    while (1)
    {
        GF_GetGUID(uuid);
        ret = terminalKeepAlive(uuid, g_mqtt_ob.clientInfo.device_id); // 系统运行数据
        sleep(30);
    }
}

void pthread_manage()
{
    pthread_t tid_publish;
    pthread_t tid_alarm;
    pthread_t tid_cmd;
    pthread_t tid_safe_data;
    pthread_t tid_alive;
    pthread_t tid_file_monitor;
    pthread_t tid_audit_log;
    pthread_t tid_net;
    pthread_t tid_usb_monito;
    pthread_t tid_baseline;
    pthread_t tid_monitor_thread;
    pthread_t tid_ssh_log_process_thread;
    pthread_t tid_cron_thread;
    int ret;

    // 主动上报线程
    ret = pthread_create(&tid_publish, NULL, publish_thread, NULL);
    if (ret != 0)
    {
        dzlog_error("pthread_create publish_thread error\n");
        return;
    }

    // 告警线程
    ret = pthread_create(&tid_alarm, NULL, alarm_thread, NULL);
    if (ret != 0)
    {
        dzlog_error("pthread_create alarm_thread error\n");
        return;
    }

    // 系统日志上报线程
    pthread_t tid_logPublish;
    ret = pthread_create(&tid_logPublish, NULL, sys_log_publish_thread, NULL);
    if (ret != 0)
    {
        dzlog_error("pthread_create sys_log_publish_thread error\n");
        return;
    }

    // 网络测试线程
    ret = pthread_create(&tid_net, NULL, netTest_thread, NULL);
    if (ret != 0)
    {
        dzlog_error("netTest_thread netTest_thread error\n");
        return;
    }

    // 心跳线程
    ret = pthread_create(&tid_alive, NULL, keep_alive_thread, NULL);
    if (ret != 0)
    {
        dzlog_error("netTest_thread keep_alive_thread error\n");
        return;
    }



    pthread_t tid_loop;
    // 定时器线程
    ret = pthread_create(&tid_loop, NULL, run_loop_thread, NULL);
    if (ret != 0)
    {
        dzlog_error("pthread_create safe_data_thread error\n");
        return;
    }
    pthread_t net_Info_loop;
    // 定时器线程
    ret = pthread_create(&net_Info_loop, NULL, net_Info_loop_thread, NULL);
    if (ret != 0)
    {
        dzlog_error("pthread_create net_Info_loop error\n");
        return;
    }

}

void setCallbacks(ST_MODEL_CTL st_model_ctl)
{
    // 装载接口(终端类)
    if (st_model_ctl.deviceFlag == 1)
    {
        // setCallbackmengbo(pFun_mb);
    }

    // 装载接口（告警类）
    if (st_model_ctl.securityFlag == 1)
    { // setCallbackSecurity(security_proc);
    }
}

static uint32_t BinToHex(const uint8_t *pData, uint32_t iLen, char *pOut, uint32_t iOutSize, bool bUppercase)
{
    if (pOut == NULL || pData == NULL || iOutSize < iLen * 2 + 1)
        return 0;

    memset(pOut, 0, iOutSize);
    const char *pHexTable = bUppercase ? "0123456789ABCDEF" : "0123456789abcdef";
    uint32_t iCount = 0;

    for (uint32_t i = 0; i < iLen; i++)
    {
        uint8_t byte = pData[i];
        pOut[iCount++] = pHexTable[(byte >> 4) & 0x0F]; // 高4位
        pOut[iCount++] = pHexTable[byte & 0x0F];        // 低4位
    }

    return iCount; // 返回实际写入字符数（不含\0）
}

/* 十六进制字符转数字的快速查找表 */
const char HexTable[] = {
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,                                                   /* 0-9 */
    -1, -1, -1, -1, -1, -1, -1,                                                     /* :@ 无效 */
    10, 11, 12, 13, 14, 15,                                                         /* A-F */
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* G-Z 无效 */
    -1, -1, -1, -1, -1, -1,                                                         /* [ _ ` 无效 */
    10, 11, 12, 13, 14, 15                                                          /* a-f */
};

static int HexToBin(const char *pHexStr, uint8_t *pOutBuf, uint32_t iOutSize)
{
    assert(pHexStr != NULL && pOutBuf != NULL && iOutSize > 0);
    if (strlen(pHexStr) % 2 != 0)
    {
        dzlog_info("input data error:%s", pHexStr);
        printf("input data error:%s", pHexStr);
        return -1;
    }

    if (iOutSize < strlen(pHexStr) / 2)
    {
        dzlog_info("out buf is not enough:%s,%d", pHexStr, iOutSize);
        return -1;
    }

    uint32_t iIndex = 0;
    uint32_t iOutIndex = 0;
    int iTmpValue = 0; // 单个十六进制字符表示的4位值
    bool bHigh = true; // 是否处理高4位

    while (pHexStr[iIndex] != '\0')
    {
        char c = pHexStr[iIndex];

        /* 跳过空白字符 */
        if (isspace(c))
        {
            iIndex++;
            continue;
        }

        /* 计算字符对应的数值 */
        int value;
        if (c >= '0' && c <= 'f')
            value = HexTable[c - '0'];
        else
        {
            dzlog_info("invalide char:%c", c);
            return -1; // 遇到无效字符
        }

        /* 组合高低4位 */
        if (bHigh)
        {
            iTmpValue = value << 4;
            bHigh = false;
        }
        else
        {
            iTmpValue |= value;
            pOutBuf[iOutIndex++] = (unsigned char)iTmpValue;
            // printf("i:%d,0x%x\n",iOutIndex-1,pOutBuf[iOutIndex-1]);
            bHigh = true;
        }

        iIndex++;
    }

    return iOutIndex; // 返回成功转换的字节数
}

// 变电日志获取
void handleBDLog(char *pBuf)
{
    // 删除原本的压缩日志文件
    remove("/PowerHarmony/SMC/tmp/log/BD_log.tar");
    int code = 200;
    cJSON *json = cJSON_Parse(pBuf);
    cJSON *send = cJSON_CreateObject();
    char node[30] = {0};
    char zone[30] = {0};
    char fileid[50] = {0};
    if (json != NULL)
    {
        cJSON *params = cJSON_GetObjectItem(json, "params");
        if (params)
        {
            char starttime[40] = {0};
            strcpy(starttime, cJSON_GetObjectItem(params, "starttime")->valuestring);
            struct tm starttm = {0};
            strptime(starttime, "%Y-%m-%d", &starttm);
            starttm.tm_hour = 0;
            starttm.tm_min = 0;
            starttm.tm_sec = 0;
            starttm.tm_isdst = -1;
            time_t mkstart = mktime(&starttm);

            char endtime[40] = {0};
            strcpy(endtime, cJSON_GetObjectItem(params, "endtime")->valuestring);
            struct tm endtm = {0};
            strptime(endtime, "%Y-%m-%d", &endtm);
            endtm.tm_hour = 23;
            endtm.tm_min = 59;
            endtm.tm_sec = 59;
            endtm.tm_isdst = -1;
            time_t mkend = mktime(&endtm);

            // 是否是今天
            time_t now = time(NULL);
            int include_today = (mkstart <= now && now <= mkend);
            dzlog_debug("start = %ld end = %ld", mkstart, mkend);
            char cmd[1024] = {0};

            sprintf(cmd, "cd /PowerHarmony/SMC/tmp/log/ && tar -cf BD_log.tar ");

            bool hasFile = false;

            if (include_today)
            {
                hasFile = true;
                strcat(cmd, "BD_MQTT.log");
            }

            time_t current_time = mkstart;

            DIR *dir;
            struct dirent *ent;
            while (current_time < mkend)
            {
                char date_str[40] = {0};
                // 转换成字符串
                struct tm current_tm;
                localtime_r(&current_time, &current_tm);
                strftime(date_str, sizeof(date_str), "%Y-%m-%d", &current_tm);
                if ((dir = opendir("/PowerHarmony/SMC/tmp/log")) == NULL)
                {
                    dzlog_error("opendir /PowerHarmony/SMC/tmp/log error");
                    code = 500;
                }

                if (code == 500)
                {
                    break;
                }

                // 扫描目录
                while ((ent = readdir(dir)) != NULL)
                {
                    if (ent->d_type != DT_REG)
                        continue; // 仅处理普通文件

                    if (strstr(ent->d_name, date_str) != NULL)
                    {
                        hasFile = true;
                        char tmp[1024] = {0};
                        sprintf(tmp, "%s %s", cmd, ent->d_name);
                        strcpy(cmd, tmp);
                        break;
                    }
                }
                dzlog_debug("cmd = %s", cmd);

                // 移动到下一天
                current_time += 24 * 3600; // 增加1天

                dzlog_debug("current_time = %d", current_time);

                closedir(dir);
            }
            if (code == 200 && hasFile)
            {
                system(cmd);
                // 文件上传
                ST_IOTA_LOGIN_RES_V1 login = {0};
                ST_IOTA_AUTH_RES_V1 auth = {0};
                login.data = &auth;
                int ret = httpFileServerLoginWithUser_v1(&login, LOGIN_USER, LOGIN_PASSWORD, "iotplatform", "password");
                if (ret)
                {
                    dzlog_error("login fileserver error");
                    code = 520;
                }
                ST_IOTA_FILE_RES file = {0};
                httpFileServerUploadFile_v1("/PowerHarmony/SMC/tmp/log/BD_log.tar", &auth, &file, NULL);
                ST_IOTA_FILE_DATA file_data = {0};
                JsonToStruct_LogFileData(file.data, &file_data);
                strcpy(node, file_data.node);
                strcpy(zone, file_data.zone);
                strcpy(fileid, file_data.fileId);

                // free
                free_s(login.message);
                free_s(auth.nonce);
                free_s(auth.token);
                free_s(auth.timestamp);

                free_s(file.data);
                free_s(file.message);

                free_s(file_data.fileId);
                free_s(file_data.node);
                free_s(file_data.zone);
            }
            else
            {
                code = 500;
                strcpy(node, cJSON_GetObjectItem(json, "node")->valuestring);
                strcpy(zone, cJSON_GetObjectItem(json, "zone")->valuestring);
            }
        }
        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(send, "msgTime", cTime);
        char uuid[64] = {0};
        GF_GetGUID(uuid);
        cJSON_AddStringToObject(send, "mid", uuid); // 主动上报的
        cJSON_AddNumberToObject(send, "code", code);
        cJSON_AddStringToObject(send, "replyId", cJSON_GetObjectItem(json, "mid")->valuestring);
        cJSON_AddStringToObject(send, "node", node);
        cJSON_AddStringToObject(send, "zone", zone);

        cJSON_AddStringToObject(send, "deviceSn", g_mqtt_ob.clientInfo.device_id);
        cJSON_AddStringToObject(send, "deviceId", g_mqtt_ob.clientInfo.device_id);
        if (code == 200)
        {
            cJSON *body = cJSON_Duplicate(params, true);
            cJSON_AddStringToObject(body, "logFile", "BD_log.tar");
            cJSON_AddStringToObject(body, "fileId", fileid);
            cJSON_AddItemToObject(send, "body", body);
        }

        char *pcJson = cJSON_PrintUnformatted(send);
        IOTA_sendMqtt("/v1/devices/Cloud_BdPortal_Res/getEagleEyeLog", pcJson, strlen(pcJson));

        cJSON_Delete(send);
        cJSON_Delete(json);

        free_s(pcJson);
        free_s(pBuf);
    }
}

// 变电转发
void handleLocalBDEvent(char *pBuf, char *topic)
{
    cJSON *json = cJSON_Parse(pBuf);
    cJSON *send = cJSON_CreateObject();
    char buf[128] = {0};
    if (json != NULL)
    {
        // 深拷贝params
        cJSON *params = cJSON_Duplicate(cJSON_GetObjectItem(json, "params"), true);
        char *tmp = strstr(topic, "/Cloud_BdPortal/");
        sprintf(buf, "/LocalMqtt/BianDian/V1%s", tmp);

        dzlog_debug("topic = %s", buf);

        char mid[64] = {0};
        strcpy(mid, cJSON_GetObjectItem(json, "mid")->valuestring);
        char zone[10] = {0};
        strcpy(zone, cJSON_GetObjectItem(json, "zone")->valuestring);
        char node[10] = {0};
        strcpy(node, cJSON_GetObjectItem(json, "node")->valuestring);
        char service[60] = {0};
        strcpy(service, cJSON_GetObjectItem(json, "service")->valuestring);

        cJSON_AddStringToObject(send, "lmid", mid); // 主动上报的
        cJSON_AddItemToObject(send, "body", params);

        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(send, "msgTime", cTime);
        cJSON_AddStringToObject(send, "msgInfo", "");
        cJSON_AddStringToObject(send, "node", node);
        cJSON_AddStringToObject(send, "zone", zone);

        char *pcJson = cJSON_PrintUnformatted(send);
        dzlog_debug("body = %s", pcJson);
        if (BD_zlog != NULL)
        {
            zlog_debug(BD_zlog, "main recesive topic = %s", topic);
            zlog_debug(BD_zlog, "main recesive body = %s", pBuf);
        }

        cJSON_Delete(json);
        cJSON_Delete(send);

        if (IOTA_sendToLocalMqtt(buf, pcJson) == MQTTASYNC_SUCCESS)
        {
            if (BD_zlog != NULL)
            {
                zlog_debug(BD_zlog, "local send topic = %s", buf);
                zlog_debug(BD_zlog, "local send body = %s", pcJson);
            }
        }

        free(pcJson);
    }
}


//TODO-YZ:PLCC 下行回调函数
void  handlePlccEvent(char *topic, char *pBuf)
{

    dzlog_debug("LOWPOWER from main receive topic = %s", topic);//add
    if(pBuf)
    {
	    dzlog_debug("LOWPOWER from main receive body = %s", pBuf);//add
    }

    cJSON *json = cJSON_Parse(pBuf);
    cJSON *send = cJSON_CreateObject();
    cJSON *body = NULL;
    if (json != NULL)
    {
	//1.解包
        char token[64] = {0};
        char requestId[200] = {0};//add
        char cTime[128] = {0};
        char cmd[64] = {0};
        strcpy(token, cJSON_GetObjectItem(json, "mid")->valuestring);
        strcpy(requestId, cJSON_GetObjectItem(json, "requestId")->valuestring);//add
        int ret = systemDate(cTime);
        strcpy(cmd, cJSON_GetObjectItem(json, "cmd")->valuestring);
	if (cJSON_HasObjectItem(json, "params"))//当params没数据时，平台不打算传params，兼容一下
	{
        	body = cJSON_Duplicate(cJSON_GetObjectItem(json, "params"), true);
	}

	//2.组包
        cJSON_AddStringToObject(send, "token", token); // 主动上报的
        cJSON_AddStringToObject(send, "requestId", requestId);//add
        cJSON_AddStringToObject(send, "msgInfo", "");
        cJSON_AddStringToObject(send, "time", cTime);
        cJSON_AddStringToObject(send, "cmd", cmd);
	if (cJSON_HasObjectItem(json, "params"))
	{
        	cJSON_AddItemToObject(send, "body", body);
	}else
	{
		cJSON_AddItemToObject(send, "body", body = cJSON_CreateObject());
	}


        char *pcJson = cJSON_PrintUnformatted(send);
        dzlog_debug("LOWPOWER   SMC send to PLCC : body = %s", pcJson);//add
        if (PLCC_zlog != NULL)
        {
            zlog_debug(PLCC_zlog, "main receive topic = %s", topic);
            zlog_debug(PLCC_zlog, "main receive body = %s", pBuf);
        }

        cJSON_Delete(json);
        cJSON_Delete(send);

	//3.下行
        if (IOTA_sendToLocalMqtt("/ext.syy.plcc/ext.syy.phSmc/S-smclink/F-PlccEvent", pcJson) == MQTTASYNC_SUCCESS)
        {
            if (PLCC_zlog != NULL)
            {
                zlog_debug(PLCC_zlog, "local send topic = /ext.syy.plcc/ext.syy.phSmc/S-smclink/F-PlccEvent");
                zlog_debug(PLCC_zlog, "local send body = %s", pcJson);
            }
        }

        free(pcJson);
    }
}

void handleBDMessageReport(char *topic, char *pBuf)
{
    cJSON *json = cJSON_Parse(pBuf);
    cJSON *send = cJSON_CreateObject();
    char buf[128] = {0};
    if (json)
    {
        cJSON *body = cJSON_Duplicate(cJSON_GetObjectItem(json, "body"), true);
        cJSON *devices = cJSON_AddArrayToObject(send, "devices");
        cJSON *device = cJSON_CreateObject();
        cJSON_AddItemToArray(devices, device);
        cJSON_AddStringToObject(device, "deviceSn", g_mqtt_ob.clientInfo.device_id);

        cJSON *services = cJSON_AddArrayToObject(device, "services");
        cJSON *service = cJSON_CreateObject();
        cJSON_AddItemToArray(services, service);

        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(service, "dataTime", cTime);
        char uuid[64] = {0};
        GF_GetGUID(uuid);
        cJSON_AddStringToObject(service, "mid", uuid); // 主动上报的
        cJSON_AddStringToObject(service, "service", "messageReport");
        cJSON_AddItemToObject(service, "data", body);

        char *pcJson = cJSON_PrintUnformatted(send);

        if (BD_zlog != NULL)
        {
            zlog_debug(BD_zlog, "report topic = %s", topic);
            zlog_debug(BD_zlog, "report body = %s", pBuf);
        }

        cJSON_Delete(json);
        cJSON_Delete(send);
        if (IOTA_sendMqtt("/v1/devices/Cloud_BdPortal_Res/messageReport", pcJson, strlen(pcJson)) == MQTTASYNC_SUCCESS)
        {
            if (BD_zlog != NULL)
            {
                zlog_debug(BD_zlog, "report to main topic = %s", topic);
                zlog_debug(BD_zlog, "report to main body = %s", pcJson);
            }
        }

        free_s(pcJson);
    }
}

void handleLocalBDBackEvent(char *pBuf, char *topic)
{
    cJSON *json = cJSON_Parse(pBuf);
    cJSON *send = cJSON_CreateObject();
    char buf[128] = {0};
    if (json)
    {
        cJSON *body = cJSON_Duplicate(cJSON_GetObjectItem(json, "body"), true);
        char *tmp = strstr(topic, "/Cloud_BdPortal_Res/");
        sprintf(buf, "/v1/devices%s", tmp);

        dzlog_debug("topic = %s", buf);

        char uuid[64] = {0};
        GF_GetGUID(uuid);
        cJSON_AddStringToObject(send, "mid", uuid); // 主动上报的
        cJSON_AddItemToObject(send, "body", body);
        cJSON_AddNumberToObject(send, "code", 200);

        char lmid[70] = {0};
        strcpy(lmid, cJSON_GetObjectItem(json, "lmid")->valuestring);
        char node[10] = {0};
        strcpy(node, cJSON_GetObjectItem(json, "node")->valuestring);
        char zone[10] = {0};
        strcpy(zone, cJSON_GetObjectItem(json, "zone")->valuestring);

        dzlog_debug("lmid = %s", lmid);

        cJSON_AddStringToObject(send, "replyId", lmid);
        cJSON_AddStringToObject(send, "node", node);
        cJSON_AddStringToObject(send, "zone", zone);

        cJSON_AddStringToObject(send, "deviceSn", g_mqtt_ob.clientInfo.device_id);
        cJSON_AddStringToObject(send, "deviceId", g_mqtt_ob.clientInfo.device_id);

        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(send, "msgTime", cTime);
        char *pcJson = cJSON_PrintUnformatted(send);
        dzlog_debug("body = %s", pcJson);
        if (BD_zlog != NULL)
        {
            zlog_debug(BD_zlog, "local recesive topic = %s", topic);
            zlog_debug(BD_zlog, "local recesive body = %s", pBuf);
        }

        cJSON_Delete(json);
        cJSON_Delete(send);
        if (IOTA_sendMqtt(buf, pcJson, strlen(pcJson)) == MQTTASYNC_SUCCESS)
        {
            if (BD_zlog != NULL)
            {
                zlog_debug(BD_zlog, "main send topic = %s", buf);
                zlog_debug(BD_zlog, "main send body = %s", pcJson);
            }
        }
        free_s(pcJson);
    }
}

//TODO-YZ:PLCC 上行回调函数
void  handleLocalPlccEvent(char *topic, char *pBuf)
{
    
    dzlog_debug("LOWPOWER from local receive topic = %s", topic);//add
    if(pBuf)
    {
	    dzlog_debug("LOWPOWER from local receive body = %s", pBuf);//add
    }

    cJSON *json = cJSON_Parse(pBuf);
    cJSON *send = cJSON_CreateObject();
    char buf[128] = {0};
    if (json)
    {
	//1.解包
	
        char uuid[64] = {0};
        GF_GetGUID(uuid);
        char replyId[70] = {0};
        char requestId[200] = {0};//add
        char cTime[128] = {0};
        int ret = systemDate(cTime);
        strcpy(replyId, cJSON_GetObjectItem(json, "token")->valuestring);
        
	if (cJSON_HasObjectItem(json, "requestId"))
	{
        	strcpy(requestId, cJSON_GetObjectItem(json, "requestId")->valuestring);//add
	}
	else
	{
		dzlog_error("from local receive no requestId");
	}

        cJSON *data = cJSON_Duplicate(cJSON_GetObjectItem(json, "data"), true);

	//2.组包
        cJSON_AddStringToObject(send, "mid", uuid); // 主动上报的
        cJSON_AddStringToObject(send, "requestId", requestId);//add
        cJSON_AddStringToObject(send, "replyId", replyId);
        cJSON_AddStringToObject(send, "msgTime", cTime);
        cJSON_AddStringToObject(send, "deviceSn", g_mqtt_ob.clientInfo.device_id);
        cJSON_AddStringToObject(send, "deviceId", g_mqtt_ob.clientInfo.device_id);
        cJSON_AddItemToObject(send, "data", data);

	//3.上行
        char *pcJson = cJSON_PrintUnformatted(send);
        dzlog_debug("LOWPOWER  SMC send to mofang  body= %s", pcJson);//add
        if (PLCC_zlog != NULL)
        {
            zlog_debug(PLCC_zlog, "local recesive topic = %s", topic);
            zlog_debug(PLCC_zlog, "local recesive body = %s", pBuf);
        }

        cJSON_Delete(json);
        cJSON_Delete(send);
        if (IOTA_sendMqtt("/v1/devices/app/response", pcJson, strlen(pcJson)) == MQTTASYNC_SUCCESS)
        {
            if (PLCC_zlog != NULL)
            {
                zlog_debug(PLCC_zlog, "main send topic = /v1/devices/app/response");
                zlog_debug(PLCC_zlog, "main send body = %s", pcJson);
            }
        }
        free_s(pcJson);
    }
}

// 子设备消息
void handleLocalSubscribeMsg(char *pBuf)
{
    cJSON *json = NULL;
    cJSON *data = NULL;
    cJSON *params = NULL;
    cJSON *service = NULL;
    cJSON *services = NULL;
    cJSON *dev = NULL;
    cJSON *devs = NULL;
    char *pcJson = NULL;

    // 构造消息并发送
    json = cJSON_CreateObject();
    if (json != NULL)
    {
        cJSON_AddItemToObject(json, "devices", devs = cJSON_CreateArray());
        cJSON_AddItemToArray(devs, dev = cJSON_CreateObject());

        cJSON_AddStringToObject(dev, "deviceSn", g_mqtt_ob.clientInfo.device_id);
        cJSON_AddItemToObject(dev, "services", services = cJSON_CreateArray());
        cJSON_AddItemToArray(services, service = cJSON_CreateObject());
        cJSON_AddStringToObject(service, "service", "childDeviceAlarm");
        char uuid[64] = {0};
        GF_GetGUID(uuid);
        cJSON_AddStringToObject(service, "mid", uuid); // 主动上报的
        cJSON_AddItemToObject(service, "data", data = cJSON_CreateObject());
        cJSON_AddStringToObject(data, "eventType", "subDeviceAccesss");
        cJSON_AddNumberToObject(data, "indication", 1);
        // cJSON_AddStringToObject(data, "severity", g_st_security_rule[i].severity);

        params = cJSON_Parse(pBuf);
        cJSON_AddItemToObject(data, "params", params);
        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(service, "eventTime", cTime);

        {
            pcJson = cJSON_PrintUnformatted(json);
        }

        cJSON_Delete(json);
        dzlog_info("msg:%s", pcJson);
        IOTA_sendMqtt("/v1/devices/child/events", pcJson, strlen(pcJson));
        free(pcJson);
    }
}

// 安全请求认证
void handleSecReq(char *pBuf)
{

}

// 设备信息通知
void handleDeviceInfo(char *pBuf)
{
    char sToken[32] = {0};
    char sDevSn[64] = {0};
    char sDevID[72] = {0};
    char sService[16] = {0};
    char sVersion[16] = {0};
    char sFirmware[16] = {0};
    char sModel[16] = {0};
    int iRet = 0;
    int iFlashUsage = 0;
    int iMemTotal = 0;
    int iFlashTotal = 0;
    int iCpuFreq = 0;
    int iMemUsage = 0;
    float fCpuTemp = 0.0;

    dzlog_debug("recvMsg buf(%s) from MCCB", pBuf);
    cJSON *pReqJson = NULL;
    pReqJson = cJSON_Parse(pBuf);
    if (pReqJson != NULL)
    {
        cJSON *pToken = cJSON_GetObjectItem(pReqJson, "token");
        if (pToken != NULL)
            strncpy(sToken, pToken->valuestring, sizeof(sToken) - 1);
        else
            dzlog_error("cJSON_GetObjectItem token failed!");

        cJSON *pSn = cJSON_GetObjectItem(pReqJson, "deviceSn");
        if (pSn != NULL)
            strncpy(sDevSn, pSn->valuestring, sizeof(sDevSn) - 1);
        else
        {
            //dzlog_error("cJSON_GetObjectItem deviceSn failed!");
        }
            

        cJSON *pID = cJSON_GetObjectItem(pReqJson, "dev");
        if (pID != NULL)
            strncpy(sDevID, pID->valuestring, sizeof(sDevID) - 1);
        else
            dzlog_error("cJSON_GetObjectItem dev failed!");

        cJSON *pService = cJSON_GetObjectItem(pReqJson, "service");
        if (pService != NULL)
            strncpy(sService, pService->valuestring, sizeof(sService) - 1);
        else
            dzlog_error("cJSON_GetObjectItem service failed!");

        cJSON *pData = cJSON_GetObjectItem(pReqJson, "data");
        if (pData != NULL)
        {
            if (strcmp(sService, "baseInfo") == 0)
            {
                cJSON *pVersion = cJSON_GetObjectItem(pData, "systemVersion");
                if (pVersion != NULL)
                    strncpy(sVersion, pVersion->valuestring, sizeof(sVersion) - 1);
                else
                    dzlog_error("cJSON_GetObjectItem systemVersion failed!");

                cJSON *pModel = cJSON_GetObjectItem(pData, "chipModel");
                if (pModel != NULL)
                    strncpy(sModel, pModel->valuestring, sizeof(sModel) - 1);
                else
                    dzlog_error("cJSON_GetObjectItem chipModel failed!");

                cJSON *pFirmware = cJSON_GetObjectItem(pData, "firmwareVersion");
                if (pFirmware != NULL)
                    strncpy(sFirmware, pFirmware->valuestring, sizeof(sFirmware) - 1);
                else
                    dzlog_error("cJSON_GetObjectItem firmwareVersion failed!");

                cJSON *pMemTotal = cJSON_GetObjectItem(pData, "memTotal");
                if (pMemTotal != NULL)
                    iMemTotal = pMemTotal->valueint;
                else
                    dzlog_error("cJSON_GetObjectItem memTotal failed!");

                cJSON *pFlashTotal = cJSON_GetObjectItem(pData, "flashTotal");
                if (pFlashTotal != NULL)
                    iFlashTotal = pFlashTotal->valueint;
                else
                    dzlog_error("cJSON_GetObjectItem flashTotal failed!");

                cJSON *pFlashUsage = cJSON_GetObjectItem(pData, "flashUsage");
                if (pFlashUsage != NULL)
                    iFlashUsage = pFlashUsage->valueint;
                else
                    dzlog_error("cJSON_GetObjectItem flashUsage failed!");

                cJSON *pCpuFreq = cJSON_GetObjectItem(pData, "cpuFreq");
                if (pCpuFreq != NULL)
                    iCpuFreq = pCpuFreq->valueint;
                else
                    dzlog_error("cJSON_GetObjectItem cpuFreq failed!");
            }
            else
            {
                cJSON *pMemUsage = cJSON_GetObjectItem(pData, "memUsage");
                if (pMemUsage != NULL)
                    iMemUsage = pMemUsage->valueint;
                else
                    dzlog_error("cJSON_GetObjectItem memUsage failed!");

                cJSON *pCpuTemp = cJSON_GetObjectItem(pData, "cpuTemp");
                if (pCpuTemp != NULL)
                    fCpuTemp = pCpuTemp->valuedouble;
                else
                    dzlog_error("cJSON_GetObjectItem cpuTemp failed!");
            }
        }
        else
            dzlog_error("cJSON_GetObjectItem data failed!");
    }
    else
        dzlog_error("cJSON_Parse failed!");

    dzlog_info("subdevice:%s %s,version:%s,fre:%d,temp:%f", sDevID, sDevSn, sVersion, iCpuFreq, fCpuTemp);
    cJSON_Delete(pReqJson);
    if (strlen(sDevSn) == 0 || strlen(sDevID) == 0)
    {
        dzlog_error("device is empty\n%s!", pBuf);
        iRet = -1;
    }

    // 判断是否认证过
    map_get(&g_SubDeviceID, sDevSn);
    if (g_SubDeviceID.ref == NULL)
    {
        dzlog_error("device has not been authorized:%s!", sDevSn);
        iRet = -2;
    }

    // 构造响应消息并发送
    cJSON *pResJson = NULL;
    char *psJson = NULL;
    pResJson = cJSON_CreateObject();
    if (pResJson != NULL)
    {
        cJSON_AddStringToObject(pResJson, "token", sToken);
        cJSON_AddStringToObject(pResJson, "deviceSn", sDevSn);
        cJSON_AddStringToObject(pResJson, "dev", sDevID);
        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(pResJson, "time", cTime);
        if (iRet == 0)
        {
            cJSON_AddStringToObject(pResJson, "ack", "true");
            cJSON_AddStringToObject(pResJson, "errmsg", "success");
        }
        else
        {
            if (iRet == -2)
            {
                cJSON_AddStringToObject(pResJson, "ack", "false");
                cJSON_AddStringToObject(pResJson, "errmsg", "not authorized");
            }
            else
            {
                cJSON_AddStringToObject(pResJson, "ack", "false");
                cJSON_AddStringToObject(pResJson, "errmsg", "Device sn is empty!");
            }
        }

        psJson = cJSON_PrintUnformatted(pResJson);
        cJSON_Delete(pResJson);

        //dzlog_info("res:%s", psJson);
        IOTA_sendToLocalMqtt("/ext.syy.mccb/ext.syy.phSmc/S-smclink/F-ReportDeviceInfo", psJson);
        free(psJson);
        psJson = NULL;
    }
    else
        dzlog_error("cJSON_CreateObject failed!");

    if (iRet != 0)
        return;

    // 构造消息发送到平台
    cJSON *pJson = cJSON_CreateObject();
    if (pJson != NULL)
    {
        char sTopic[64] = {0};
        cJSON_AddStringToObject(pJson, "deviceSn", g_mqtt_ob.clientInfo.device_id);
        cJSON_AddStringToObject(pJson, "subDeviceSn", sDevSn);
        char uuid[64] = {0};
        GF_GetGUID(uuid);
        cJSON_AddStringToObject(pJson, "mid", uuid); // 主动上报的
        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(pJson, "msgTime", cTime);
        if (strcmp(sService, "baseInfo") == 0)
        {
            cJSON_AddStringToObject(pJson, "systemVersion", sVersion);
            cJSON_AddStringToObject(pJson, "chipModel", sModel);
            cJSON_AddStringToObject(pJson, "firmwareVersion", sFirmware);
            cJSON_AddNumberToObject(pJson, "memTotal", iMemTotal);
            cJSON_AddNumberToObject(pJson, "flashTotal", iFlashTotal);
            cJSON_AddNumberToObject(pJson, "flashUsage", iFlashUsage);
            cJSON_AddNumberToObject(pJson, "cpuFreq", iCpuFreq);
            strncpy(sTopic, "/v1/devices/subDevice/subDeviceInfo", sizeof(sTopic) - 1);
        }
        else
        {
            cJSON_AddNumberToObject(pJson, "memUsage", iMemUsage);
            cJSON_AddNumberToObject(pJson, "cpuTemp", iCpuFreq);
            strncpy(sTopic, "/v1/devices/subDevice/subDevicePerformance", sizeof(sTopic) - 1);
        }

        psJson = cJSON_PrintUnformatted(pJson);
        cJSON_Delete(pJson);
        dzlog_info("send platform:%s", psJson);
        IOTA_sendMqtt(sTopic, psJson, strlen(psJson));
        free(psJson);
    }
    else
        dzlog_error("cJSON_CreateObject1 failed!");
}

// 设备在线状态通知
void handleDeviceStatus(char *pBuf)
{
    char sToken[32] = {0};
    char sDevSn[64][64] = {0};
    int iStatus[64] = {0};
    int iCount = 0;
    int iRet = 0;
    bool bPrint = false;

    cJSON *pReqJson = NULL;
    pReqJson = cJSON_Parse(pBuf);
    if (pReqJson != NULL)
    {
        cJSON *pToken = cJSON_GetObjectItem(pReqJson, "token");
        if (pToken != NULL)
            strncpy(sToken, pToken->valuestring, sizeof(sToken) - 1);
        else
            dzlog_error("cJSON_GetObjectItem token failed!");

        cJSON *pBody = cJSON_GetObjectItem(pReqJson, "body");
        if (pBody != NULL)
        {
            for (int i = 0; i < cJSON_GetArraySize(pBody); i++)
            {
                cJSON *pItem = cJSON_GetArrayItem(pBody, i);
                if (pItem != NULL)
                {
                    cJSON *pDeviceSN = cJSON_GetObjectItem(pItem, "deviceSn");
                    if (pDeviceSN != NULL)
                    {
                        char sSn[64] = {0};
                        strncpy(sSn, pDeviceSN->valuestring, sizeof(sSn) - 1);

                        // 判断是否认证过
                        map_get(&g_SubDeviceID, sSn);
                        if (g_SubDeviceID.ref == NULL)
                        {
                            dzlog_error("device has not been authorized:%s!", sSn);
                            continue;
                        }

                        cJSON *pValue = cJSON_GetObjectItem(pItem, "val");
                        if (pValue == NULL)
                        {
                            dzlog_warn("cJSON_GetObjectItem val failed!");
                            pValue = cJSON_GetObjectItem(pItem, "event");
                            if (pValue == NULL)
                                dzlog_warn("cJSON_GetObjectItem event failed!");
                        }

                        if (pValue != NULL)
                        {
                            char sValue[4] = {0};
                            strncpy(sValue, pValue->valuestring, sizeof(sValue) - 1);
                            int iVal = 0;
                            if (strcmp(sValue, "1") == 0)
                                iVal = 1;

                            strcpy(sDevSn[iCount], sSn);
                            iStatus[iCount] = iVal;
                            iCount++;
                            if(iVal == 0)
                                bPrint = true;
                        }
                    }
                    else
                    {
                        //dzlog_error("cJSON_GetObjectItem deviceSn failed!");
                        break; // 没有代表这不是一个状态消息
                    }
                }
                else
                    dzlog_error("cJSON_GetObjectItem get array item failed!");
            }
        }
        else
            dzlog_error("cJSON_GetObjectItem body failed!");
    }
    else
        dzlog_error("cJSON_Parse failed!");

    cJSON_Delete(pReqJson);

    if(bPrint && iCount > 1)
        dzlog_info("msg:%s", pBuf);

    dzlog_info("subdevice status iCount:%d", iCount);
    // 构造消息发送到平台
    if (iCount > 0)
    {
        cJSON *pJson = cJSON_CreateObject();
        if (pJson != NULL)
        {
            char uuid[64] = {0};
            GF_GetGUID(uuid);
            cJSON_AddStringToObject(pJson, "mid", uuid); // 主动上报的
            char cTime[128] = {0};
            int ret = systemDate(cTime);
            cJSON_AddStringToObject(pJson, "msgTime", cTime);
            cJSON_AddStringToObject(pJson, "deviceSn", g_mqtt_ob.clientInfo.device_id);
            cJSON *pData = cJSON_CreateArray();
            cJSON_AddItemToObject(pJson, "data", pData);
            for (int i = 0; i < iCount; i++)
            {
                cJSON *pItem = cJSON_CreateObject();
                cJSON_AddItemToArray(pData, pItem);
                cJSON_AddStringToObject(pItem, "subDeviceSn", sDevSn[i]);
                cJSON_AddNumberToObject(pItem, "onlineStatus", iStatus[i]);
            }

            char *psJson = cJSON_PrintUnformatted(pJson);
            cJSON_Delete(pJson);
            //dzlog_info("send platform:%s", psJson);
            IOTA_sendMqtt("/v1/devices/subDevice/onlineStatus", psJson, strlen(psJson));
            free(psJson);
        }
        else
            dzlog_error("cJSON_CreateObject1 failed!");
    }
}

// 查询CCO认证信息响应处理
void handleAuthInfo(char *pBuf)
{
    char sToken[32] = {0};
    char sTask[8] = {0};
    char sPort[8] = {0};
    char sFrame[2048] = {0};
    int iRet = 0;

    dzlog_debug("recvMsg buf(%s) from Schedule", pBuf);
    cJSON *pReqJson = NULL;
    pReqJson = cJSON_Parse(pBuf);
    if (pReqJson != NULL)
    {
        cJSON *pToken = cJSON_GetObjectItem(pReqJson, "token");
        if (pToken != NULL)
            strncpy(sToken, pToken->valuestring, sizeof(sToken) - 1);
        else
            dzlog_error("cJSON_GetObjectItem token failed!");
            
        cJSON *pData = cJSON_GetObjectItem(pReqJson, "data");
        if (pData != NULL)
        {
            cJSON *pFrame = cJSON_GetObjectItem(pData, "frame");
            if (pFrame != NULL)
                strncpy(sFrame, pFrame->valuestring, sizeof(sFrame) - 1);
            else
                dzlog_error("cJSON_GetObjectItem frame failed!");

            cJSON *pTask = cJSON_GetObjectItem(pData, "taskID");
            if (pTask != NULL)
                strncpy(sTask, pTask->valuestring, sizeof(sTask) - 1);
            else
                dzlog_error("cJSON_GetObjectItem taskID failed!");

            cJSON *pPort = cJSON_GetObjectItem(pData, "port");
            if (pPort != NULL)
                strncpy(sPort, pPort->valuestring, sizeof(sPort) - 1);
            else
                dzlog_error("cJSON_GetObjectItem port failed!");
        }
        else
            dzlog_error("cJSON_GetObjectItem data failed!");
    }
    else
        dzlog_error("cJSON_Parse failed!");

    dzlog_info("task:%s port:%s,frame:%s", sTask,sPort,sFrame);
    cJSON_Delete(pReqJson);
    if (strlen(sFrame) == 0)
    {
        dzlog_error("frame is empty\n%s!", pBuf);
        iRet = -1;
    }

    if (iRet != 0)
        return;

    //计量协议帧数据解析
    uint8_t sBinFrame[1024] = {0};
    int iOutSize = HexToBin(sFrame,sBinFrame,sizeof(sBinFrame));

    uint8_t iAFN = 0;
    uint32_t iD1 = 0;
    uint16_t iLen = 0;
    uint8_t sContent[1024] = {0};
    UnPackJLFrame(sBinFrame,iOutSize,&iAFN,iD1,sContent,&iLen);
    dzlog_info("AFN:0x%x D1:0x%x,iOutSize:%d,iLen:%d,content:0x%x,0x%x,0x%x,0x%x,0x%x", iAFN,iD1,iOutSize,iLen,sContent[0],sContent[1],sContent[2],sContent[3],sContent[4]);
    
    //批量查询认证信息的响应处理
    if(iD1 == (uint32_t)((uint32_t)0xE8 << 24 | (uint32_t)0x04 << 16 | (uint32_t)0x03 << 8 | 0x42))
    {
        //返回节点总数量，则开始查询节点认证信息
        if(iLen == 5 && sContent[4] == 0x00)
        {
            //构造计量协议帧
            g_iLastStartNo = 0;                         //节点起始序列号置0
            uint8_t sData[4] = {0};
            sData[0] = 0x01;
            memcpy(sData+1,(uint16_t*)g_iLastStartNo,2);
            sData[3] = NODE_STEP;

            uint8_t sOutBinFrame[1024] = {0};
            uint16_t iOutSize = 0;
            uint32_t iD1 = (uint32_t)0xE8 << 24 | (uint32_t)0x03 << 16 | (uint32_t)0x03 << 8 | 0x42;
            PackJLFrame(0x03,iD1,sData,sizeof(sData),sOutBinFrame,&iOutSize);

            char sOutFrame[2048] = {0};
            BinToHex(sOutBinFrame,iOutSize,sOutFrame,sizeof(sOutFrame),true);
            dzlog_info("frame:%s", sOutFrame);

            // 构造消息发送到采集调度
            cJSON *pJson = cJSON_CreateObject();
            if (pJson != NULL)
            {
                cJSON_AddStringToObject(pJson, "token", sToken);
                char cTime[128] = {0};
                int ret = systemDate(cTime);
                cJSON_AddStringToObject(pJson, "time", cTime);

                cJSON *pData = cJSON_CreateObject();
                cJSON_AddItemToObject(pJson, "data", pData);
                char sSeq[12] = {0};
                snprintf(sSeq,sizeof(sSeq),"%d",g_iFrameSeq);
                cJSON_AddStringToObject(pData, "taskID", sSeq);
                cJSON_AddStringToObject(pData, "port", "1F");
                cJSON_AddStringToObject(pData, "portParam", "1200-8-E-1-500-1000");
                cJSON_AddStringToObject(pData, "timeout", "10");
                cJSON_AddStringToObject(pData, "frame", sOutFrame);

                char *psJson = cJSON_PrintUnformatted(pJson);
                cJSON_Delete(pJson);
                dzlog_info("send to scheduler:");
                IOTA_sendToLocalMqtt("/svc.tasksched/ext.syy.phSmc/S-meter/F-ProxyFrame", psJson);
                free(psJson);
            }
            else
                dzlog_error("cJSON_CreateObject failed!");

            return;
        }
        else                            //返回从节点认证信息，则上报平台并继续查询
        {
            //解析帧里面的数据内容
            uint16_t iTotal = *((uint16_t*)sContent);
            g_iLastStartNo = *((uint16_t*)(sContent+2));
            uint8_t iCount = sContent[4];
            dzlog_info("total:%d,start:%d,count:%d",iTotal,g_iLastStartNo,iCount);

            uint8_t *pTemp = sContent + 5;
            for(int i=0;i<iCount;i++)
            {
                uint8_t sAddr[6] = {0};
                memcpy(sAddr,pTemp,6);

                uint8_t iResult = *(pTemp + 6);

                char sEsn[25] = {0};
                memcpy(sEsn,pTemp + 7,24);
                uint16_t iLen = *((uint16_t*)(pTemp + 31));
                dzlog_info("iResult:%d,sEsn:%s,iLen:%d,addr:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",iResult,sEsn,iLen,sAddr[0],sAddr[1],sAddr[2],sAddr[3],sAddr[4],sAddr[5]);

                //将节点地址存入MAP表
                map_get(&g_CcoStaDeviceID, sEsn);
                if (g_CcoStaDeviceID.ref != NULL)
                {
                    // //认证结果有变则修改
                    // if(iResult != (uint8_t)(*(g_CcoStaDeviceID.ref)))
                    // {
                    //     uint8_t *piResult = *(g_CcoStaDeviceID.ref);
                    //     *piResult = iResult;
                    // }
                }
                else
                {
                    uint8_t *psAddr = (uint8_t*)malloc(sizeof(uint8_t)*6);
                    memcpy(psAddr,sAddr,6);
                    map_set(&g_CcoStaDeviceID, sEsn, (void*)psAddr);
                }

                // 构造认证消息发送到平台
                cJSON *pJson = cJSON_CreateObject();
                if (pJson != NULL)
                {
                    cJSON_AddStringToObject(pJson, "deviceSn", g_mqtt_ob.clientInfo.device_id);
                    cJSON_AddStringToObject(pJson, "subDeviceSn", sEsn);
                    char uuid[64] = {0};
                    GF_GetGUID(uuid);
                    cJSON_AddStringToObject(pJson, "mid", uuid); // 主动上报的
                    char cTime[128] = {0};
                    int ret = systemDate(cTime);
                    cJSON_AddStringToObject(pJson, "msgTime", cTime);
                    if (iResult == 1)
                        cJSON_AddNumberToObject(pJson, "secResult", 0);         //成功
                    else
                        cJSON_AddNumberToObject(pJson, "secResult", 1);

                    char *psJson = cJSON_PrintUnformatted(pJson);
                    cJSON_Delete(pJson);
                    dzlog_info("send platform:");
                    IOTA_sendMqtt("/v1/devices/subDevice/subDeviceSecResult", psJson, strlen(psJson));
                    free(psJson);
                }
                else
                    dzlog_error("cJSON_CreateObject failed!");

                if(iResult == 1)
                    pTemp = pTemp + (6+1+24+2+128);
                else
                    pTemp = pTemp + (6+1+24+2);
            }

            //查询完则不需要继续查询
            if(iTotal == g_iLastStartNo + iCount)
            {
                dzlog_info("has query all sub node data");
                g_bIsQuering = false;
            }
            else
            {
                //构造量测协议帧
                g_iLastStartNo += NODE_STEP;                         //节点起始序列号变更
                uint8_t sData[4] = {0};
                sData[0] = 0x01;
                memcpy(sData+1,(uint16_t*)g_iLastStartNo,2);
                sData[3] = NODE_STEP;

                uint8_t sOutBinFrame[1024] = {0};
                uint16_t iOutSize = 0;
                uint32_t iD1 = 0xE8 << 24 | 0x03 << 16 | 0x03 << 8 | 0x42;
                PackJLFrame(0x03,iD1,sData,sizeof(sData),sOutBinFrame,&iOutSize);

                char sOutFrame[2048] = {0};
                BinToHex(sOutBinFrame,iOutSize,sOutFrame,sizeof(sOutFrame),true);
                dzlog_info("frame:%s", sOutFrame);

                // 构造消息发送到采集调度
                cJSON *pJson = cJSON_CreateObject();
                if (pJson != NULL)
                {
                    cJSON_AddStringToObject(pJson, "token", sToken);
                    char cTime[128] = {0};
                    int ret = systemDate(cTime);
                    cJSON_AddStringToObject(pJson, "time", cTime);

                    cJSON *pData = cJSON_CreateObject();
                    cJSON_AddItemToObject(pJson, "data", pData);
                    char sSeq[12] = {0};
                    snprintf(sSeq,sizeof(sSeq),"%d",g_iFrameSeq);
                    cJSON_AddStringToObject(pData, "taskID", sSeq);
                    cJSON_AddStringToObject(pData, "port", "1F");
                    cJSON_AddStringToObject(pData, "portParam", "1200-8-E-1-500-1000");
                    cJSON_AddStringToObject(pData, "timeout", "10");
                    cJSON_AddStringToObject(pData, "frame", sOutFrame);

                    char *psJson = cJSON_PrintUnformatted(pJson);
                    cJSON_Delete(pJson);
                    dzlog_info("send to scheduler:");
                    IOTA_sendToLocalMqtt("/svc.tasksched/ext.syy.phSmc/S-meter/F-ProxyFrame", psJson);
                    free(psJson);
                }
                else
                    dzlog_error("cJSON_CreateObject failed!");
            }
        }
    }
}

// CCO认证有关的上报事件处理
void handleReportEvent(char *pBuf)
{
    char sToken[32] = {0};
    char sAddr[32] = {0};
    char sPort[8] = {0};
    char sD1[16] = {0};
    char sFrame[2048] = {0};
    int iRet = 0;

    dzlog_debug("recv report event(%s) from Schedule", pBuf);
    cJSON *pReqJson = NULL;
    pReqJson = cJSON_Parse(pBuf);
    if (pReqJson != NULL)
    {
        cJSON *pToken = cJSON_GetObjectItem(pReqJson, "token");
        if (pToken != NULL)
            strncpy(sToken, pToken->valuestring, sizeof(sToken) - 1);
        else
            dzlog_error("cJSON_GetObjectItem token failed!");
            
        cJSON *pData = cJSON_GetObjectItem(pReqJson, "data");
        if (pData != NULL)
        {
            //frame
            cJSON *pFrame = cJSON_GetObjectItem(pData, "frame");
            if (pFrame != NULL)
                strncpy(sFrame, pFrame->valuestring, sizeof(sFrame) - 1);
            else
                dzlog_error("cJSON_GetObjectItem frame failed!");

            cJSON *pAddr = cJSON_GetObjectItem(pData, "srcAddr");
            if (pAddr != NULL)
                strncpy(sAddr, pAddr->valuestring, sizeof(sAddr) - 1);
            else
                dzlog_error("cJSON_GetObjectItem srcAddr failed!");

            cJSON *pPort = cJSON_GetObjectItem(pData, "port");
            if (pPort != NULL)
                strncpy(sPort, pPort->valuestring, sizeof(sPort) - 1);
            else
                dzlog_error("cJSON_GetObjectItem port failed!");

            //数据标识编码
            cJSON *pDI = cJSON_GetObjectItem(pData, "DI");
            if (pDI != NULL)
                strncpy(sD1, pDI->valuestring, sizeof(sD1) - 1);
            else
                dzlog_error("cJSON_GetObjectItem DI failed!");
        }
        else
            dzlog_error("cJSON_GetObjectItem data failed!");
    }
    else
        dzlog_error("cJSON_Parse failed!");

    dzlog_info("D1:%s port:%s,frame:%s", sD1,sPort,sFrame);
    cJSON_Delete(pReqJson);

    uint8_t sBinD1[4] = {0};
    HexToBin(sD1,sBinD1,sizeof(sBinD1));
    uint32_t iD1 = (uint32_t)sBinD1[0] << 24 | (uint32_t)sBinD1[1] << 16 | (uint32_t)sBinD1[2] << 8 | sBinD1[3];
    dzlog_debug("D1:0x%x", iD1);
    
    //上报身份认证完成标志
    if(iD1 == (uint32_t)0xE8 << 24 | (uint32_t)0x05 << 16 | (uint32_t)0x05 << 8 | 0x41)
    {
        dzlog_info("all sta auth has been finished(g_bIsQuering:%d)", g_bIsQuering);
        uint8_t sBinFrame[30] = {0};             
        HexToBin(sFrame,sBinFrame,sizeof(sBinFrame));           //将数据标识内容转成BIN数据

        //将CCO的ESN和地址存入MAP
        uint8_t sEsn[25] = {0};
        memcpy(sEsn,sBinFrame+6,24);
        map_get(&g_CcoStaDeviceID, sEsn);
        if (g_CcoStaDeviceID.ref == NULL)
        {
            uint8_t *psAddr = (uint8_t*)malloc(sizeof(uint8_t)*6);
            memcpy(psAddr,sBinFrame,6);
            map_set(&g_CcoStaDeviceID, sEsn, (void*)psAddr);
        }

        //没查询则开始查询节点认证信息
        if(!g_bIsQuering)
        {
            //构造计量协议帧中应用数据
            g_iLastStartNo = 0;                         //节点起始序列号置0
            uint8_t sData[4] = {0};
            sData[0] = 0x01;
            memcpy(sData+1,(uint16_t*)g_iLastStartNo,2);
            sData[3] = NODE_STEP;

            //构造计量协议帧
            uint8_t sOutBinFrame[1024] = {0};
            uint16_t iOutSize = 0;
            uint32_t iD1 = (uint32_t)0xE8 << 24 | (uint32_t)0x03 << 16 | (uint32_t)0x03 << 8 | 0x42;
            PackJLFrame(0x03,iD1,sData,sizeof(sData),sOutBinFrame,&iOutSize);

            char sOutFrame[2048] = {0};
            BinToHex(sOutBinFrame,iOutSize,sOutFrame,sizeof(sOutFrame),true);
            dzlog_info("frame:%s", sOutFrame);

            // 构造消息发送到采集调度
            cJSON *pJson = cJSON_CreateObject();
            if (pJson != NULL)
            {
                cJSON_AddStringToObject(pJson, "token", sToken);
                char cTime[128] = {0};
                int ret = systemDate(cTime);
                cJSON_AddStringToObject(pJson, "time", cTime);

                cJSON *pData = cJSON_CreateObject();
                cJSON_AddItemToObject(pJson, "data", pData);
                char sSeq[12] = {0};
                snprintf(sSeq,sizeof(sSeq),"%d",g_iFrameSeq);
                cJSON_AddStringToObject(pData, "taskID", sSeq);
                cJSON_AddStringToObject(pData, "port", "1F");
                cJSON_AddStringToObject(pData, "portParam", "1200-8-E-1-500-1000");
                cJSON_AddStringToObject(pData, "timeout", "10");
                cJSON_AddStringToObject(pData, "frame", sOutFrame);

                char *psJson = cJSON_PrintUnformatted(pJson);
                cJSON_Delete(pJson);
                dzlog_info("send to scheduler:");
                IOTA_sendToLocalMqtt("/svc.tasksched/ext.syy.phSmc/S-meter/F-ProxyFrame", psJson);
                free(psJson);
            }
            else
                dzlog_error("cJSON_CreateObject failed!");
        }
        else
            dzlog_info("Querying node info!");
    }
    else if(iD1 == (uint32_t)0xE8 << 24 | (uint32_t)0x05 << 16 | (uint32_t)0x05 << 8 | 0x40)        //增强认证信息
    {
        dzlog_info("recv strong auth info");

        if(strlen(sFrame) <= 0)
        {
            dzlog_warn("frame is empty!");
            return;
        }
        
        char sCpuID[49] = {0};                  //芯片ID
        char sESN[49] = {0};                    //ESN(HEX字符)
        char sRandom[33] = {0};                 //随机数
        char sSigValue[129] = {0};              //签名数据

        memcpy(sCpuID,sFrame+12,sizeof(sCpuID)-1);
        memcpy(sESN,sFrame+11+sizeof(sCpuID),sizeof(sESN)-1);
        memcpy(sRandom,sFrame+10+sizeof(sCpuID)+sizeof(sESN),sizeof(sRandom)-1);
        memcpy(sSigValue,sFrame+9+sizeof(sCpuID)+sizeof(sESN)+sizeof(sRandom),sizeof(sSigValue)-1);

        uint8_t sDevSn[25] = {0};             //ESN(普通字符)
        HexToBin(sESN,sDevSn,sizeof(sDevSn));

        // 发送验签请求到前置服务
        cJSON *pReqJson = NULL;
        pReqJson = cJSON_CreateObject();
        if (pReqJson != NULL)
        {         
            cJSON_AddStringToObject(pReqJson, "ESN", sDevSn);
            cJSON_AddStringToObject(pReqJson, "esamID", sCpuID);
            cJSON_AddStringToObject(pReqJson, "signdata", sSigValue);
            cJSON_AddStringToObject(pReqJson, "plaintext", sRandom);

            char *psJson = NULL;
            psJson = cJSON_PrintUnformatted(pReqJson);
            cJSON_Delete(pReqJson);

            dzlog_info("subdevice auth req:%s", psJson);
            iRet = httpSubDeviceAuthReq(psJson);
            if(iRet != 0)
            {
                iRet = -2;
                dzlog_error("httpSubDeviceAuthReq failed!");
                printf("httpSubDeviceAuthReq failed!\n");
            }
            else
            {
                dzlog_info("httpSubDeviceAuthReq success");
                printf("httpSubDeviceAuthReq success\n");
            }
            free(psJson);
        }
        else
            dzlog_error("cJSON_CreateObject failed!");
    }
}

//查询CCO下子设备认证信息
void QueryCcoSubDevice()
{
    dzlog_info("start to do QueryCcoSubDevice");
    //没查询则开始查询节点认证信息
    if(!g_bIsQuering)
    {

        //构造计量协议帧
        g_iLastStartNo = 0;                         //节点起始序列号置0
        uint8_t sData[4] = {0};
        sData[0] = 0x01;
        dzlog_info("start to do QueryCcoSubDevice11111");
        memcpy(sData+1,&g_iLastStartNo,2);
        sData[3] = NODE_STEP;
        dzlog_info("start to do QueryCcoSubDevice22222");
        uint8_t sOutBinFrame[1024] = {0};
        uint16_t iOutSize = 0;
        uint32_t iD1 = (uint32_t)0xE8 << 24 | (uint32_t)0x03 << 16 | (uint32_t)0x03 << 8 | 0x42;
        dzlog_info("start to do PackJLFrame");
        PackJLFrame(0x03,iD1,sData,sizeof(sData),sOutBinFrame,&iOutSize);
        dzlog_info("PackJLFrame end,sOutBinFrame:%s", sOutBinFrame);
        char sOutFrame[2048] = {0};
        BinToHex(sOutBinFrame,iOutSize,sOutFrame,sizeof(sOutFrame),true);
        dzlog_info("frame:%s", sOutFrame);

        // 构造消息发送到采集调度
        cJSON *pJson = cJSON_CreateObject();
        if (pJson != NULL)
        {
            cJSON_AddStringToObject(pJson, "token", "sToken");
            char cTime[128] = {0};
            int ret = systemDate(cTime);
            cJSON_AddStringToObject(pJson, "time", cTime);

            cJSON *pData = cJSON_CreateObject();
            cJSON_AddItemToObject(pJson, "data", pData);
            char sSeq[12] = {0};
            snprintf(sSeq,sizeof(sSeq),"%d",g_iFrameSeq);
            cJSON_AddStringToObject(pData, "taskID", sSeq);
            cJSON_AddStringToObject(pData, "port", "1F");
            cJSON_AddStringToObject(pData, "portParam", "1200-8-E-1-500-1000");
            cJSON_AddStringToObject(pData, "timeout", "10");
            cJSON_AddStringToObject(pData, "frame", sOutFrame);

            char *psJson = cJSON_PrintUnformatted(pJson);
            cJSON_Delete(pJson);
            dzlog_info("send to scheduler:");
            IOTA_sendToLocalMqtt("/svc.tasksched/ext.syy.phSmc/S-meter/F-ProxyFrame", psJson);
            free(psJson);
        }
        else
            dzlog_error("cJSON_CreateObject failed!");
    }
    else
        dzlog_info("Is querying node info!");
}

//发送CCO或STA增强认证到采集调度程序
void SendAuthToScheduler(uint8_t *psAddr)
{
    //构造计量协议帧
    uint8_t sOutBinFrame[1024] = {0};
    uint16_t iOutSize = 0;
    uint32_t iD1 = (uint32_t)0xE8 << 24 | (uint32_t)0x02 << 16 | (uint32_t)0x04 << 8 | 0x42;
    PackJLFrame(0x03,iD1,psAddr,6,sOutBinFrame,&iOutSize);

    char sOutFrame[2048] = {0};
    BinToHex(sOutBinFrame,iOutSize,sOutFrame,sizeof(sOutFrame),true);
    dzlog_info("frame:%s", sOutFrame);

    // 构造消息发送到采集调度
    cJSON *pJson = cJSON_CreateObject();
    if (pJson != NULL)
    {
        cJSON_AddStringToObject(pJson, "token", "sToken");
        char cTime[128] = {0};
        int ret = systemDate(cTime);
        cJSON_AddStringToObject(pJson, "time", cTime);

        cJSON *pData = cJSON_CreateObject();
        cJSON_AddItemToObject(pJson, "data", pData);
        char sSeq[12] = {0};
        snprintf(sSeq,sizeof(sSeq),"%d",g_iFrameSeq);
        cJSON_AddStringToObject(pData, "taskID", sSeq);
        cJSON_AddStringToObject(pData, "port", "1F");
        cJSON_AddStringToObject(pData, "portParam", "1200-8-E-1-500-1000");
        cJSON_AddStringToObject(pData, "timeout", "10");
        cJSON_AddStringToObject(pData, "frame", sOutFrame);

        char *psJson = cJSON_PrintUnformatted(pJson);
        cJSON_Delete(pJson);
        dzlog_info("send to scheduler:");
        IOTA_sendToLocalMqtt("/svc.tasksched/ext.syy.phSmc/S-meter/F-ProxyFrame", psJson);
        free(psJson);
    }
    else
        dzlog_error("cJSON_CreateObject failed!");
}